import mx.utils.Delegate;

import gugga.utils.Listener;
import gugga.common.EventDescriptor;
import gugga.sequence.FictiveTask;

import test_framework.test.unit.TestCase;

/**
 * @author vladimir
 */
class guggaLibTests.ListenerTest
		extends TestCase
{
	private var isEventRaised:Boolean;
	private var eventRaisedCount:Number;
	
	// variables need for the merging object test:
	private var dataProperty1:String = "dataProperty1";
	private var dataProperty1Value:String = "dataProperty1Value";
	private var dataProperty2:String = "dataProperty2";
	private var dataProperty2Value:String = "dataProperty2Value";
	
	public function ListenerTest()
	{
		super();
		this.isEventRaised = false;
		this.eventRaisedCount = 0;
	}
	
	public function testConstructor()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
				
		var dataObject:Object = new Object();
		
		var isListeningOnlyOnce:Boolean = false;
		
		var listener:Listener = new Listener(
				eventDescriptor, 
				Delegate.create(this, onEventRaised), 
				dataObject, 
				isListeningOnlyOnce);
		
		assertNotNull(
				"listener should not be null after creation", 
				listener);
		assertNotUndefined(
				"listener should not be undefined after creation", 
				listener);
		
		assertFalse(
				"listener should not listen right after creation, use start() should to start listening", 
				listener.Listening);
	}
	
	public function testCreate()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
				
		var dataObject:Object = new Object();
		
		var isListeningOnlyOnce:Boolean = false;
		
		var listener:Listener = Listener.create(
				eventDescriptor, 
				Delegate.create(this, onEventRaised), 
				dataObject, 
				isListeningOnlyOnce);
		
		assertNotNull("listener should not be null after creation", listener);
		assertNotUndefined("listener should not be undefined after creation", listener);
		
		assertTrue(
				"listener should be listening after create(), create() calls start()", 
				listener.Listening);
		
		// raise "completed" event:
		fictiveEventSource.start();
		
		assertTrue(
				"event should be caught and consumed", 
				this.isEventRaised);
		
		// listener is not listening only once, so the following event should 
		// be caught too:
		fictiveEventSource.start();
		assertEquals(
				"this is not a single time listener, second event should be caught and consumed too",
				2, 
				this.eventRaisedCount);
	}
	
	public function testCreateSingleTimeListener()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
		
		var listener:Listener = Listener.createSingleTimeListener(
				eventDescriptor, 
				Delegate.create(this, onEventRaised));
		
		assertNotNull("listener should not be null after creation", listener);
		assertNotUndefined("listener should not be undefined after creation", listener);
		
		assertTrue(
				"listener should be listening after create(), create() calls start()", 
				listener.Listening);
		
		// raise "completed" event:
		fictiveEventSource.start();
		
		assertTrue(
				"event should be caught and consumed", 
				this.isEventRaised);
		
		// listener is listening only once, so the following event should not 
		// be caught:
		fictiveEventSource.start();
		assertEquals(
				"this is a single time listener, second event should not be caught",
				1, 
				this.eventRaisedCount);
	}
	
	public function testCreateMergingListener()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
		
		var dataObject:Object = new Object();
		
		var listener:Listener = Listener.createMergingListener(
				eventDescriptor, 
				Delegate.create(this, onEventRaised), 
				dataObject);
		
		assertNotNull("listener should not be null after creation", listener);
		assertNotUndefined("listener should not be undefined after creation", listener);
		
		assertTrue(
				"listener should be listening after create(), create() calls start()", 
				listener.Listening);
		
		// raise "completed" event:
		fictiveEventSource.start();
		
		assertTrue(
				"event should be caught and consumed", 
				this.isEventRaised);
		
		// listener is not listening only once, so the following event should 
		// be caught too:
		fictiveEventSource.start();
		assertEquals(
				"this is not a single time listener, second event should be caught and consumed too",
				2, 
				this.eventRaisedCount);
	}
	
	public function testCreateSingleTimeMergingListener()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
		
		var dataObject:Object = new Object();
		
		var listener:Listener = Listener.createSingleTimeMergingListener(
				eventDescriptor, 
				Delegate.create(this, onEventRaised), 
				dataObject);
		
		assertNotNull("listener should not be null after creation", listener);
		assertNotUndefined("listener should not be undefined after creation", listener);
		
		assertTrue(
				"listener should be listening after create(), create() calls start()", 
				listener.Listening);
		
		// raise "completed" event:
		fictiveEventSource.start();
		
		assertTrue(
				"event should be caught and consumed", 
				this.isEventRaised);
		
		// listener is listening only once, so the following event should not 
		// be caught:
		fictiveEventSource.start();
		assertEquals(
				"this is a single time listener, second event should not be caught",
				1, 
				this.eventRaisedCount);
	}
	
	public function testHandleEventObjectMerging()
	{
		this.reset();
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"completed");
		
		var dataObject:Object = new Object();
		dataObject[dataProperty1] = dataProperty1Value;
		dataObject[dataProperty2] = dataProperty2Value;
		
		var listener:Listener = Listener.createMergingListener(
				eventDescriptor, 
				Delegate.create(this, onEventRaisedAssertMergedObject), 
				dataObject);
		
		// raise "completed" event:
		fictiveEventSource.start();
	}
	
	private function onEventRaised()
	{
		this.isEventRaised = true;
		this.eventRaisedCount++;
	}
	
	private function onEventRaisedAssertMergedObject(aMergedObject:Object)
	{
		assertNotNull(
				"the merged object should have dataProperty1 property that's not null", 
				aMergedObject[this.dataProperty1]);
		assertNotUndefined(
				"the merged object should have dataProperty1 property that's not undefined", 
				aMergedObject[this.dataProperty1]);
		assertEquals(
				"dataProperty1's value should be " + this.dataProperty1Value, 
				this.dataProperty1Value, 
				aMergedObject[this.dataProperty1]);
		
		assertNotNull(
				"the merged object should have dataProperty2 property that's not null", 
				aMergedObject[this.dataProperty2]);
		assertNotUndefined(
				"the merged object should have dataProperty2 property that's not undefined", 
				aMergedObject[this.dataProperty2]);
		assertEquals(
				"dataProperty2's value should be " + this.dataProperty2Value, 
				this.dataProperty2Value, 
				aMergedObject[this.dataProperty2]);
	}
	
	private function reset()
	{
		this.isEventRaised = false;
		this.eventRaisedCount = 0;
	}
}